using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
using Microsoft.Office.Server.SocialData;
using Microsoft.SharePoint.Taxonomy;

namespace E4D.Solutions.SPRNuGet.Features.E4D.Solutions.SPRNuGet_Feature
{
    /// <summary>
    /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>

    [Guid("619b9544-5e2c-4d1e-8c4a-bf3f86ce6de2")]
    public class E4DSolutionsEventReceiver : SPFeatureReceiver
    {
        // Uncomment the method below to handle the event raised after a feature has been activated.

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            // === enable rating field the folder. === //
            #region const members
            const string averageRatingId = "5a14d1ab-1513-48c7-97b3-657a5ba6c742";
            const string ratingCountId = "b1996002-9167-45e5-a4df-b2c41c6723c7";
            #endregion
            #region enable rating
            try
            {
                SPList list = (properties.Feature.Parent as SPSite).RootWeb.Lists.TryGetList("SharePoint Repository for NuGet");
                if (list != null)
                {
                    SPField avgFieldByGuid = list.ParentWeb.AvailableFields[new Guid(averageRatingId)];
                    SPField ratingFieldByGuid = list.ParentWeb.AvailableFields[new Guid(ratingCountId)];
                    if (avgFieldByGuid != null && !list.Fields.ContainsField(avgFieldByGuid.StaticName))
                    {
                        list.Fields.AddFieldAsXml(avgFieldByGuid.SchemaXml, true, SPAddFieldOptions.AddToAllContentTypes);
                    }
                    if (ratingFieldByGuid != null && !list.Fields.ContainsField(ratingFieldByGuid.StaticName))
                    {
                        list.Fields.AddFieldAsXml(ratingFieldByGuid.SchemaXml, false, SPAddFieldOptions.AddToAllContentTypes);
                    }
                    list.Update();
                    Repropagate(list);
                }
            }
            catch (Exception ex)
            {
                // write to log
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("SPRNuGet Repository", TraceSeverity.Monitorable, EventSeverity.Error), TraceSeverity.Monitorable, "Error enabling rating: {0}", ex.Message);
            }
            #endregion

            // === create taxonomy set and enable field === //
            #region taxonomy
            SPSite site = properties.Feature.Parent as SPSite;
            ConnectTaxonomyField(site, new Guid("{9E9B94DA-D3A6-44C5-B739-3F935EB5ECD9}"), "SPRNuGet", "PackagesTerms");
            #endregion
        }


        // Uncomment the method below to handle the event raised before a feature is deactivated.

        //public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        //{
        //}


        // Uncomment the method below to handle the event raised after a feature has been installed.

        //public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        //{
        //}


        // Uncomment the method below to handle the event raised before a feature is uninstalled.

        //public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        //{
        //}

        // Uncomment the method below to handle the event raised when a feature is upgrading.

        //public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        //{
        //}

        #region helper methods
        private static void Repropagate(SPList list)
        {
            SocialRatingManager ratingManager = new SocialRatingManager(SPServiceContext.Current);
            string baseUrl = list.ParentWeb.Url;
            if (baseUrl.EndsWith("/", StringComparison.OrdinalIgnoreCase))
            {
                baseUrl = baseUrl.TrimEnd(new char[] { '/' });
            }
            foreach (SPListItem item in list.Items)
            {
                string itemUrl = item.Url;
                if (itemUrl.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    itemUrl = itemUrl.TrimStart(new char[] { '/' });
                }
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    ratingManager.PropagateRating(new Uri(baseUrl + "/" + itemUrl));
                });
            }
        }

        public static void ConnectTaxonomyField(SPSite site, Guid fieldId, string termGroup, string termSetName)
        {
            if (site.RootWeb.Fields.Contains(fieldId))
            {
                TaxonomySession session = new TaxonomySession(site);
                if (session.DefaultKeywordsTermStore != null)
                {
                    // get the default metadata service application                 
                    var termStore = session.DefaultKeywordsTermStore;
                    
                    // check if SPRNuGet group is avaliable, and if not create it.
                    var group = termStore.Groups.GetByName(termGroup);
                    if (group == null)
                    {
                        group = termStore.CreateGroup(termGroup);
                        termStore.CommitAll();
                    }

                    // check if SPRNuGet termset is avaliable, and if not create it.
                    var termSet = group.TermSets.GetByName(termSetName);
                    if (termSet == null)
                    {
                        termSet = group.CreateTermSet(termSetName);
                        termSet.IsOpenForTermCreation = true;
                        termSet.CreateTerm("NuGet", 1033);
                        termStore.CommitAll();
                    }

                    TaxonomyField field = site.RootWeb.Fields[fieldId] as TaxonomyField;

                    // connect the web level field to the specified term                 
                    UpdateField(field, termSet);
                    site.RootWeb.Update();

                    // update the taxonomy field of the SPRNuGet folder with the right term store.
                    SPList list = site.RootWeb.Lists.TryGetList("SharePoint Repository for NuGet");
                    if (list != null && list.Fields.Contains(fieldId))
                    {
                        TaxonomyField listField = list.Fields[fieldId] as TaxonomyField;
                        UpdateField(listField, termSet);
                        list.Update();
                    }
                    else
                    {
                        SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("SPRNuGet Repository", TraceSeverity.Monitorable, EventSeverity.Error), TraceSeverity.Monitorable, "No list was found on site: {0}", site.Url);
                    }
                }
                else
                {
                    SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("SPRNuGet Repository", TraceSeverity.Monitorable, EventSeverity.Error), TraceSeverity.Monitorable, "No keyword term store found for site: {0}",site.Url);
                }
            }
            else
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("SPRNuGet Repository", TraceSeverity.Monitorable, EventSeverity.Error), TraceSeverity.Monitorable, "field {0} not found in site {1}", fieldId,site.Url);
            }
        }

        private static void UpdateField(TaxonomyField field, TermSet termSet)
        {
            field.SspId = termSet.TermStore.Id;
            field.TermSetId = termSet.Id;
            field.TargetTemplate = string.Empty;
            field.EnforceUniqueValues = false;
            field.Open = true;
            field.AnchorId = Guid.Empty;
            field.Update();
        }
        #endregion
    }
    #region extensions
    public static class TaxonomyExtensions
    {
        public static Group GetByName(this GroupCollection groupCollection, string name)
        {
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentException("Taxonomy group name cannot be empty", "name");
            }
            foreach (var group in groupCollection)
            {
                if (group.Name == name) { return group; }
            }
            //throw new ArgumentOutOfRangeException("name", name, "Could not find the taxonomy group");
            return null;
        }

        public static TermSet GetByName(this TermSetCollection termSets, string name)
        {
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentException("Term set name cannot be empty", "name");
            }
            foreach (var termSet in termSets)
            {
                if (termSet.Name == name) { return termSet; }
            }
            //throw new ArgumentOutOfRangeException("name", name, "Could not find the term set");
            return null;
        }
    }
    #endregion
}
